package cn.myzf.fort.access.accesscommon.processoutput.reader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public abstract class AbstractProcessReader
        implements Runnable {

    /** the process to read from. */
    protected Process m_Process;

    /** whether to use stdout or stderr. */
    protected boolean m_Stdout;

    /**
     * Initializes the reader.
     *
     * @param process	the process to monitor
     * @param stdout	whether to read stdout or stderr
     */
    public AbstractProcessReader(Process process, boolean stdout) {
        m_Process = process;
        m_Stdout = stdout;
    }

    /**
     * Returns whether the reader is for stdout or stderr.
     *
     * @return		true if for stdout
     */
    public boolean isStdout() {
        return m_Stdout;
    }

    /**
     * Returns the underlying {@link Process} object.
     *
     * @return		the process object
     */
    public Process getProcess() {
        return m_Process;
    }

    /**
     * For processing the line read from stdout/stderr.
     *
     * @param line	the output line
     */
    protected abstract void process(String line);

    /**
     * Reads the data from the process.
     */
    @Override
    public void run() {
        String 		line;
        BufferedReader reader;

        try {
            if (m_Stdout)
                reader = new BufferedReader(new InputStreamReader(m_Process.getInputStream()), 1024);
            else
                reader = new BufferedReader(new InputStreamReader(m_Process.getErrorStream()), 1024);

            while (m_Process.isAlive()) {
                try {
                    line = reader.readLine();
                }
                catch (IOException ioe) {
                    // has process stopped?
                    if (ioe.getMessage().toLowerCase().contains("stream closed"))
                        return;
                    else
                        throw ioe;
                }
                if (line != null)
                    process(line);
            }

            // make sure all data has been read
            while (true) {
                try {
                    line = reader.readLine();
                    if (line == null)
                        break;
                    else
                        process(line);
                }
                catch (Exception e) {
                    break;
                }
            }
        }
        catch (Exception e) {
            System.err.println("Failed to read from " + (m_Stdout ? "stdout" : "stderr") + " for process #" + m_Process.hashCode() + ":");
            e.printStackTrace();
        }
    }
}
